package com.tt.payee.filter.webFliters;

import com.tt.payee.business.BusinessException;
import com.tt.payee.business.BusinessStatus;
import com.tt.payee.common.Constant;
import com.tt.payee.enums.PlatformEnum;
import com.tt.payee.utils.JwtTokenUtil;
import com.tt.payee.utils.RedisUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.tomcat.util.buf.MessageBytes;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author ：Tang
 * @date ：Created in 2020/8/19 14:43
 * @description：
 * @modified By：
 * @version: $
 */
@Component
public class TokenFilter implements HandlerInterceptor {

    @Autowired
    RedisUtils redisUtils;


    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String token = request.getHeader("access_token");
        String platform = request.getHeader("platform");

        //获取路由地址
        Object a = findCoyoteRequest(request);
        Field coyoteRequest = a.getClass().getDeclaredField("coyoteRequest");
        coyoteRequest.setAccessible(true);
        Object b = coyoteRequest.get(a);

        Field uriMB = b.getClass().getDeclaredField("uriMB");
        uriMB.setAccessible(true);
        MessageBytes c = (MessageBytes)uriMB.get(b);

        String path = c.getString();

        //判断是不是不用登录就可以过的接口
        for (String pUrl : new InterceptorConfig().getPassUrl()) {
            if (path.equals(pUrl)) {
                return true;
            }
        }

        //看看token 是不是不存在
        if (StringUtils.isBlank(token)) {
            throw new BusinessException(BusinessStatus.ILLEGAL_TOKEN);
        }

        String userId = null;

        try {
            userId = JwtTokenUtil.getIdFromToken(token);
        } catch (Exception e) {
            throw new BusinessException(BusinessStatus.TOKEN_EXPIRED);
        }

        //判断入口 token 是不是过期了
        if (platform.equals(PlatformEnum.PC.getCode().toString()) && redisUtils.get(Constant.BACKEND_TOKEN_PRE + ":" + userId) == null) {
            throw new BusinessException(BusinessStatus.TOKEN_EXPIRED);
        }

        //判断请求的来源
        if (
                (
                        platform.equals(PlatformEnum.H5.getCode().toString()) ||
                                platform.equals(PlatformEnum.WX_MINI_PROGRAM.getCode().toString()) ||
                                platform.equals(PlatformEnum.APP_ANDROID.getCode().toString()) ||
                                platform.equals(PlatformEnum.APP_IOS.getCode().toString())
                )
                        && redisUtils.get(Constant.FRONTEND_TOKEN_PRE + ":" + userId) == null
        ) {
            throw new BusinessException(BusinessStatus.TOKEN_EXPIRED);
        }

        //判断token是否过期
        if(JwtTokenUtil.isTokenExpired(token)){
            throw new BusinessException(BusinessStatus.TOKEN_EXPIRED);
        }

        return true;
    }


    //根据Field获得对应的Class
    private Class getClassByName(Class classObject, String name){
        Map<Class, List<Field>> fieldMap = new HashMap<>();
        Class returnClass = null;
        Class tempClass = classObject;
        while (tempClass != null) {
            fieldMap.put(tempClass, Arrays.asList(tempClass .getDeclaredFields()));
            tempClass = tempClass.getSuperclass();
        }

        for(Map.Entry<Class,List<Field>> entry: fieldMap.entrySet()){
            for (Field f : entry.getValue()) {
                if(f.getName().equals(name)){
                    returnClass = entry.getKey();
                    break;
                }
            }
        }
        return returnClass;
    }

    //递归遍历父类寻找coyoteRequest Field
    private Object findCoyoteRequest(Object request)  throws Exception {
        Class a = getClassByName(request.getClass(),"request");
        Field request1 = a.getDeclaredField("request");
        request1.setAccessible(true);
        Object b = request1.get(request);
        if(getClassByName(b.getClass(),"coyoteRequest") == null){
            return findCoyoteRequest(b);
        }else{
            return b;
        }
    }
}
